package com.lm.common.core.util;

import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.util.Base64;

/**
 * AES加密解密，基于AES-128-ECB加密模式
 *
 * @author lm
 * @date 2019/9/17 14:57
 */
public class AesEncryptUtil {

    private static final String DEFAULT_CHARSET = "UTF-8";
    private static final String KEY_AES = "AES";
    private static final String AES_CBC_PKCS5_PADDING = "AES/CBC/PKCS5PADDING";
    private static final String C_KEY = "QEMAWN2UMK8L5PEI";
    private static final String IV = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
    /**
     * 必须为16位
     */
    private static final int IV_LENGTH = 16;

    /**
     * JDK只支持AES-128加密，也就是密钥长度必须是128bit；参数为密钥key，key的长度小于16字符时用"0"补充，key长度大于16字符时截取前16位
     **/
    private static SecretKeySpec create128BitsKey(String key) {
        if (StringUtils.isBlank(key)) {
            key = "";
        }
        byte[] data = null;
        StringBuffer buffer = new StringBuffer(IV_LENGTH);
        buffer.append(key);
        // 小于16后面补0
        while (buffer.length() < IV_LENGTH) {
            buffer.append("0");
        }
        // 大于16，截取前16个字符
        if (buffer.length() > IV_LENGTH) {
            buffer.setLength(IV_LENGTH);
        }
        try {
            data = buffer.toString().getBytes(DEFAULT_CHARSET);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return new SecretKeySpec(data, KEY_AES);
    }

    /**
     * 创建128位的偏移量，iv的长度小于16时后面补0，大于16，截取前16个字符;
     *
     * @param iv
     * @return
     */
    private static IvParameterSpec create128BitsIV(String iv) {
        if (iv == null) {
            iv = "";
        }
        byte[] data = null;
        StringBuffer buffer = new StringBuffer(IV_LENGTH);
        buffer.append(iv);
        while (buffer.length() < IV_LENGTH) {
            buffer.append("0");
        }
        if (buffer.length() > IV_LENGTH) {
            buffer.setLength(IV_LENGTH);
        }
        try {
            data = buffer.toString().getBytes(DEFAULT_CHARSET);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return new IvParameterSpec(data);
    }

    /**
     * 填充方式为Pkcs5Padding时，最后一个块需要填充χ个字节，填充的值就是χ，也就是填充内容由JDK确定
     *
     * @param sSrc
     * @param sKey
     * @param iv
     * @return
     */
    public static byte[] encryptByte(byte[] sSrc, String sKey, String iv) {
        try {
            SecretKeySpec skeySpec = create128BitsKey(sKey);
            IvParameterSpec ivParameterSpec = create128BitsIV(iv);

            Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
            byte[] encryptedContent = cipher.doFinal(sSrc);

            return encryptedContent;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    private static String encrypt(String sSrc, String sKey, String iv) throws Exception {
        if (sKey == null || sSrc == null) {
            return null;
        }
        return Base64.getEncoder().encodeToString(encryptByte(sSrc.getBytes(), sKey, iv));
    }

    public static String encrypt(String sSrc) {
        if (sSrc == null) {
            return null;
        }
        return Base64.getEncoder().encodeToString(encryptByte(sSrc.getBytes(), C_KEY, IV));
    }

    private static byte[] decryptByte(byte[] sSrc, String sKey, String iv) {
        try {
            SecretKeySpec key = create128BitsKey(sKey);
            IvParameterSpec ivParameterSpec = create128BitsIV(iv);

            Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING);
            cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
            byte[] decryptedContent = cipher.doFinal(sSrc);

            return decryptedContent;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    private static String decrypt(String sSrc, String sKey, String iv) throws Exception {
        if (sKey == null || sSrc == null) {
            return null;
        }
        return new String(decryptByte(Base64.getDecoder().decode(sSrc), sKey, iv));
    }

    public static String decrypt(String sSrc) throws Exception {
        if (sSrc == null) {
            return null;
        }
        return new String(decryptByte(Base64.getDecoder().decode(sSrc), C_KEY, IV));
    }

    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1) {
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    public static void main(String[] args) throws Exception {

        // 此处使用AES-128-ECB加密模式，key需要为16位。
        String testCKey = "1234567890123456";
        // 需要加密的字串
        String cSrc = "abcdefghigklmnopqrstuvwxyz0123456789";
        String iv = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
        // 加密
        System.out.println(AesEncryptUtil.encrypt(cSrc, testCKey, iv));
        String enString = Base64Util.encode(AesEncryptUtil.encryptByte(cSrc.getBytes(), testCKey, iv));
        System.out.println("加密后的字串:" + enString);
        System.out.println("加密后正确的:8Z3dZzqn05FmiuBLowExK0CAbs4TY2GorC2dDPVlsn/tP+VuJGePqIMv1uSaVErr");
        System.out.println("8Z3dZzqn05FmiuBLowExK0CAbs4TY2GorC2dDPVlsn/tP+VuJGePqIMv1uSaVErr".length());
        System.out.println("加密后的字串是：" + enString.length());
        // 解密
        String DeString = AesEncryptUtil.decrypt(enString, testCKey, iv);
        System.out.println("解密后的字串是:" + DeString);

        String str = "KbomTMaxBibeDTgDeJ0FZxYnMWdWAY8khFzlUs+dE3/S6Dpb5GiUsIWFzrOUnLbvDD6+vbN+X94W/Ow48UsxBMPy7Ep0pnQ8Un1P3AUTorPEcptJnF0FnRapaPWa6v+OmNuoFjeK2GXUZmCm5GBilEKMLwHbVLJDbJHsiFHJf5TwnSYmFjilG4XdqcTBOuiY3HOZmgxH3bOYCp0B5YHFMDRj6xzUqWVb+pH2FDmhXm0DysJUoPlWN6WASIrsy581/pkLgFTdCmKBoSH0NP3YsxvbDMfkB8ZHhqRUjo0wYW24L4LsDAu/+OkhfE6p/Oe0gNQ0I7kOQ1jzGFHmUFApBGUM71DtmWYcKfUmd9woyr2EN8bSaiF5h542stzSCjvBVGoPy7+pxYGPTkJZK4QwRZ30wMDf2dj2TdYozOYBn+e9a4h6FdAwhEeQo1KvpsS0V5bXVSv3JiaCymAnNFWBBa7pXS3vN+jI9Y7buPjm3e5Dk/m35UyPyUOWlr/OqKXv5crEfSSvH9HKzw80ZWV5F8KvLoZye9b2xcQ9RUzKohVcjkF7hkxK2d4i/MGPfqotC8FWhh/IUJ+I5fgqTjmYxwBpq8L1JHyg3zNTDvqPpVeLgBg+d3LaVQnEwJhRoKn1x5Jin8DeCC1BISYDlOeZpAlMBgZkWDquiUhJ5yxZR7dB90Q2JraZZpstHK+vkMxYlBnQonLyhQpQ5BvpGViu5PAG2imRZ7bTghDhUL/gLRu5RLZAHBn2hXUu+sPEFAnwirzEZfDCPLtfstPHGoe36J23djj1XmaAhZs21zhb5y5zUJo0Paj8rb8fkxubpxqaw9IxwJvTF/DPACkpQnICp8vR+BSFp2ZlkDiUXeahQ1f816mQk6GWnwLa6WnTjimM1hDBvxPyvBVekjNeJPE+q0UtR/LO8wIQkSo8EAfSr07n259tb1TjY3D3PKcP29hI9yVPzWoXjRozW8Nk4w2ewh5mwIbwQ2u+B20AmTQ87I9WN1WVGP/7qav4S1PYf1ubVG7sIyQkKJEXNUAA99cg3kdeanoId0TtaATLVK/YSIN46Pa62lMysWJeSF7sI+NehPGEGaXE7dSAa+lknrT+JlbsXaIZI+HJpaNh9dMvTCUpczqSF4UCPFDPg1xqxoRa3Z2okokd8tbpUJzjFlbI6d6Y5Aa7YBuuunnn/vWeAhXraBEOkKqD8Jq2zYD3NsPdp6CxGUS4vaMA/UOVuZ9bSWrnYtOfvCJmTtRL9i31sy62TDqw6VtO57It+K/zIMGiowl4t0VQDVJ4OlLKrX3CDrcBi2X/EkUDxZRkqQMyadcxaelOJpGpyrN5SoRE6kvTrOn5rHqHVxDDyPOBNec/yBNib3GIY+SmB47SFgrACo1W7tJ4zujcijgHZ1yqSDkc/99s+aRfAzrk7aGNX/lgzETAOy1feAPciWO5fwEnz1HSx+upEVNSIQeoGsa+lRxG0XIk5pNxacslAtlIkLQagmAZP83W79tcjvqBOiVreCa2JSjt3dyE3Zd/PYNuSZl19PHOJKff3HosKcz5onLJ7mdFp8gtdZ4TboGAsN8Kc+rZrPS4ZAoKV/uBn4i7quxRFbEZX5VCACE/WJGNTOUfzFfOlcU8vB9qqrtGFcO3Eb+RGILSXRNAGaoCxbUqgZWldLI91iptJPOFSrGPRx9g0+1Hm+sQ1YDZ3zfSUGpT8SUfUiCwm/bycdLGPZd43wNY";
        String DeStr = AesEncryptUtil.decrypt(str, C_KEY, iv);
        System.out.println("解密后的字串是:" + DeStr);
    }

}
